#pragma onece

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <cstdio>
#include <error.h>
#include <unistd.h>
#include <cstring>

#define gCreater 1
#define gUser 2

const std::string gcomm_path = "/home/lxp/111/Shm";
int gproj_id = 0x66;
int gShmSize = 4096;

class Shm
{
    void GetKey()
    {
        _key = ftok(_path.c_str(),_proj_id);
        if(_key < 0)
        {
            perror("ftok");
        }
    }

    bool GetForCreat()
    {
        if(_id == gCreater)
        {
            _shm_id = shmget(_key,gShmSize,IPC_CREAT | IPC_EXCL | 0666);
            if(_shm_id < 0 )
            {
                perror("shmget");
                return false;
            }
            std::cout << "shm creat sucess !" << std::endl;            
            return true;
        }   
        return false;
    }

    bool GetForUse()
    {
        if(_id == gUser)
        {
            _shm_id = shmget(_key,4096,IPC_CREAT | 0666);
            if(_shm_id < 0 )
            {
                perror("shmget");
                return false;
            }
            std::cout << "shm get sucess !" << std::endl;
            return true;
        }
        return false;
    }

    void* Attach()
    {
        void* add = shmat(_shm_id,nullptr,0);
        if(add == nullptr)
        {
            perror("shmat");
        }
        std::cout << "attach shm success " << std::endl;
        return add;
    }

    void Detach(void* arr)
    {
        if(arr == nullptr)
            return ;
        shmdt(arr);
        //std::cout << "shm deach m " << std::endl;
    }
public:
    Shm(const std::string& comm_path ,int proj_id,int who)
    :_path(comm_path)
    ,_proj_id(proj_id)
    ,_id(who)
    {
        GetKey();

        if(_id == gCreater)
            GetForCreat();
        if(_id == gUser)
            GetForUse();
        _addr = Attach();

        std::cout << "shmid : " << _shm_id << std::endl;
        std::cout << "key : " << ToHex() << std::endl;
    }

    ~Shm()
    {
        Detach(_addr);
        if(_id == gCreater)
        {
            shmctl(_shm_id,IPC_RMID,nullptr);
        }
        std::cout << "shm remove !" << std::endl;

    }

    std::string ToHex()
    {
        char buff[1024];
        snprintf(buff,sizeof(buff),"%0xh",_key);
        return buff;
    }

    void* Addr()
    {
        return _addr;
    }

    void Zero()
    {
        if(_addr)
        {
            memset(_addr,'\0',gShmSize);
        }
    }

private:
    int _shm_id;
    key_t _key;
    std::string _path;
    int _proj_id;
    int _id;
    void* _addr = nullptr;
};
